﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using SharePointClient.SPWebService.Lists;
using System.Xml;

namespace SharePointClient
{
    /// <summary>
    /// A List in a Website
    /// </summary>
    public class List : WSSBase,IDisposable
    {
        public const string WebService = "_vti_bin/Lists.asmx";
        public enum Template
        {
            Announcements=104,
            Contacts=105,
            CustomList=100,
            CustomListInDatasheetView=120,
            DataSources=110,
            DiscussionBoard=108,
            DocumentLibrary=101,
            Events=106,
            FormLibrary=115,
            Issues=1100,
            Links=103,
            PictureLibrary=109,
            Survey=102,
            Tasks=107
        }
        FieldCollection myFieldCollection;
        ViewCollection myViews=null;
        DocumentCollection myDocuments = null;

        internal Lists lists = new Lists();

       
        internal List(Connection connection,Uri url, Guid listID)
            : base(connection,url)
        {
            Guid = listID;
        }
        internal List(Connection connection,Uri url, XmlNode partialData)
            : base(connection,url)
        {
            MetaDataElement=partialData;
            Guid = new Guid(SelectItem("/wss:List/@ID"));
            HasNoData = true;
        }
        /// <summary>
        /// Refresh if not refreshed allready
        /// </summary>
        public void Load()
        {
            if (NeedRefresh) Refresh();
        }
        /// <summary>
        /// Get list information from List
        /// </summary>
        public override void Refresh()
        {
            lists.Url = Uri.ToString() + WebService;
            lists.Credentials = Credentials;
            ProgressEventArgs p=myConnection.DoProgress("Loading ListAndView "+Guid+" from \""+Uri+"\"");
            try
            {
                MetaDataElement = (XmlElement)lists.GetListAndView(Guid.ToString(), "");
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Failed Loading List " + Guid + " with View. Trying without View. ("+e.Message+")");
                MetaDataElement = (XmlElement)lists.GetList(Guid.ToString());
            }
            myFieldCollection = new FieldCollection(Select("//wss:Fields")[0]);
            if (myViews!=null) myViews.Dispose();
            if (myDocuments != null) myDocuments.Refresh();
            myViews=null;
            NeedRefresh = false;
            p.Operation = "Loaded List '" + Title + " from \"" + Uri + "\"";
            p.State = BeforeOrAfter.After;
            myConnection.UpdateProgress(p);
        }
        public XmlAttributeCollection Attributes
        {
            get { return Select("//wss:List")[0].Attributes; }
        }
        public Template ServerTemplate
        {
            get { Load(); return (Template) Convert.ToInt32(this.Attributes["ServerTemplate"].Value); }
        }
        public Connection Connection { get { return myConnection; } }
        public FieldCollection Fields
        {
            get
            {
                Load();
                return myFieldCollection;
            }
        }
        public string Title
        {
            get
            {
                string title=SelectItem("//wss:List/@Title");
                if (title == "")
                {
                    Load(); return SelectItem("//wss:List/@Title");
                } else return title;
            }
        }
        public string Description
        {
            get
            {
                Load(); return SelectItem("//wss:List/@Description");
            }
        }
        public DateTime Created
        {
            get
            {
                Load(); 
                string dt = SelectItem("//wss:List/@Created");
                return DateTimeFromWSS(dt);
            }
        }
        public DateTime Modified
        {
            get
            {
                Load();
                string dt = SelectItem("//wss:List/@Modified");
                return DateTimeFromWSS(dt);
            }
        }
        public DateTime LastDeleted
        {
            get
            {
                Load();
                string dt = SelectItem("//wss:List/@LastDeleted");
                return DateTimeFromWSS(dt);
            }
        }
        public bool EnableVersioning
        {
            get
            {
                Load();
                return Convert.ToBoolean(SelectItem("//wss:List/@EnableVersioning"));
            }
        }
        public bool EnableModeration
        {
            get
            {
                Load();
                return Convert.ToBoolean(SelectItem("//wss:List/@EnableModeration"));
            }
        }
        public bool EnableAttachments
        {
            get
            {
                Load();
                return Convert.ToBoolean(SelectItem("//wss:List/@EnableAttachments"));
            }
        }
        public bool Hidden
        {
            get
            {
                Load();
                return Convert.ToBoolean(SelectItem("//wss:List/@Hidden"));
            }
        }
        public bool EnableMinorVersion
        {
            get
            {
                Load();
                return Convert.ToBoolean(SelectItem("//wss:List/@EnableMinorVersion"));
            }
        }
        public bool RequireCheckout
        {
            get
            {
                Load();
                return Convert.ToBoolean(SelectItem("//wss:List/@RequireCheckout"));
            }
        }
        public int ItemCount
        {
            get
            {
                Load();
                return Convert.ToInt32(SelectItem("//wss:List/@ItemCount"));
            }
        }
        public View DefaultView
        {
            get 
            {
                Load();
                XmlNode v = Select("//wss:View")[0];
                if (v != null)
                {
                    Guid vguid=new Guid(Select(v,"@Name")[0].Value);
                    if (myConnection.Cached(vguid)) return (View) myConnection[vguid];
                    else return new View(myConnection,Uri, Guid, v);
                }
                else return null;
            }
        }

        public ViewCollection Views
        {
            get 
            {
                if (myViews!=null) return myViews;
                else return myViews=new ViewCollection(myConnection,Uri, Guid);
            }
        }
        public override string ToString()
        {
            if (Title=="") return base.ToString();
            else return Title;
        }
        public string RootFolder
        {
            get { Load(); return SelectItem("//wss:List/@RootFolder"); }
        }
        public Uri RootFolderUri
        {
            get
            {
                Uri ret; if (Uri.TryCreate(Uri, SelectItem("//wss:List/@RootFolder"),out ret)) return ret;
                else return Uri;
            }
        }
        public Guid WebID
        {
            get { Load(); string webid = SelectItem("//wss:List/@WebId"); return new Guid(webid); }
        }
        #region IDisposable Member

        public void Dispose()
        {
            if (lists!=null) lists.Dispose();
            if (myViews!=null) myViews.Dispose();
            if (myDocuments != null) myDocuments.Dispose();
        }

        #endregion

        public XmlNode GetData()
        {
            return GetData(DefaultView);
        }
        
        public XmlNode GetData(View view)
        {
            Load();
            if (view==null || view.ListGuid!=Guid)
                return lists.GetListItems(Guid.ToString(),"",null,null,"100",QueryOptions,WebID.ToString());
            else return lists.GetListItems(Guid.ToString(), view.Guid.ToString(), view.Query, view.ViewFields, view.RowLimit, QueryOptions, WebID.ToString());
            
        }
        public XmlNode GetData(XmlNode query, XmlNode fields,int count)
        {
            return lists.GetListItems(Guid.ToString(), "", query, fields, count.ToString(), QueryOptions, WebID.ToString());
        }
        /// <summary>
        /// Returns a default QueryOptions-Element for GetListItems()
        /// </summary>
        public XmlNode QueryOptions
        {
            get
            {
                XmlDocument x = new XmlDocument();
                x.LoadXml("<QueryOptions><IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns><DateInUtc>FALSE</DateInUtc><ViewAttributes Scope=\"Recursive\" /></QueryOptions>");
                return x;
            }
        }

        public void Fill(DataTable t, View view)
        {
            XmlNode data = GetData(view);
            t.Clear();
            t.TableName = Title;

            List<string> fields=null;
            if (view!=null) fields= view.FieldsInView;
            foreach (XmlNode n in Select(data, "/rs:data/z:row"))
            {
                /*
                foreach (XmlAttribute a in n.Attributes)
                    if ((a.Value!="") && (fields==null || fields.Contains(a.Name.Replace("ows_",""))))
                    {
                        Field f = myFieldCollection[a.Name.Replace("ows_","")];
                        if (f == null) System.Diagnostics.Debugger.Break();
                        if (!t.Columns.Contains(f.Name))
                        {
                            DataColumn c = new DataColumn(f.Name, f.DataType);
                            c.Caption = f.DisplayName;
                            t.Columns.Add(c);
                        }
                    }
                 */
                DataRow r=t.NewRow();
                foreach (XmlAttribute a in n.Attributes)
                {
                    Field f = myFieldCollection[a.Name.Replace("ows_", "")];
                    if (f == null) f = myFieldCollection[a.Name.Replace("ows_", "")];
                    if (!t.Columns.Contains(f.ColumnName)) t.Columns.Add(f.ColumnName, f.DataType);
                    string val = a.Value;
///if (val.IndexOf(";#") > 0) val = val.Substring(val.IndexOf(";#") + 2); // Remove Internal IDs
                    r[f.ColumnName] = f.ConvertToType(val);
                }
                t.Rows.Add(r);
            }
            t.AcceptChanges();
        }
        public void Fill(XmlNode query,DataTable t)
        {
            XmlNode data = lists.GetListItems(Guid.ToString(), "",query, null, "1000", null, WebID.ToString()); 
            t.Clear();
            t.TableName = Title;
            foreach (XmlNode n in Select(data, "/rs:data/z:row"))
            {
                foreach (XmlAttribute a in n.Attributes)
                {
                    Field f = myFieldCollection[a.Name.Replace("ows_", "")];
                    if (f == null) System.Diagnostics.Debugger.Break();
                    if (!t.Columns.Contains(f.Name))
                    {
                        DataColumn c = new DataColumn(f.Name, f.DataType);
                        c.Caption = f.DisplayName;
                        t.Columns.Add(c);
                    }
                }
                DataRow r = t.NewRow();
                foreach (XmlAttribute a in n.Attributes)
                {
                    Field f = myFieldCollection[a.Name.Replace("ows_", "")];
                    if (f == null) f = myFieldCollection[a.Name.Replace("ows_", "")];
                    string val = a.Value;
                    if (val.IndexOf(";#") > 0) val = val.Substring(val.IndexOf(";#") + 2); // Remove Internal IDs
                    r[f.Name] = f.ConvertToType(val);
                }
                t.Rows.Add(r);
            }
            t.AcceptChanges();
        }
        public bool CheckQuery(XmlNode query)
        {
            //TODO:CheckQuery -- program
            return true;
        }
        private static List<string>Cutter(string sql)
        {
            // TODO:Check if Cutter is functional
            List<string> cutted=new List<string>();
            
            int begin=0;int end=0;
            bool space=true;
            while (end<sql.Length)
            {
                if (sql[end]==' ' && ! space)
                {
                    cutted.Add(sql.Substring(begin,end-begin-1));
                    begin=++end;
                    space=true;
                    continue;
                } 
                if (sql[end]!=' ') space=false;
                if (sql[end]=='>' || sql[end]=='<')
                    if (sql.Length>end+1 && sql[end+1]=='=')
                        cutted.Add(sql.Substring(end++,1));
                    cutted.Add(sql.Substring(end++,1));
            }
            if (sql.Substring(begin,sql.Length-begin).Trim()!="") cutted.Add(sql.Substring(begin,sql.Length-begin).Trim());
            return cutted;
        }
        public DocumentCollection Documents
        {
            get
            {
                switch (ServerTemplate)
                {
                    case Template.DocumentLibrary:
                    case Template.FormLibrary:
                    case Template.PictureLibrary:

                        if (myDocuments == null) myDocuments = new DocumentCollection(this);
                        return myDocuments;
                        
                    default:
                        return null;
                        
                }
            }
        }
        
        public static XmlNode CreateQuery(string sql)
        {
            XmlDocument qry=new XmlDocument();
            XmlNode act;
            qry.AppendChild(qry.CreateElement("Query").AppendChild(act=qry.CreateElement("Where")));
            return qry.FirstChild;
            //TODO:Query
        }
       
    }
 
}
